package lock

import (
	"fmt"
	"sync"
)

type MyRwLock struct {
	mx *sync.Mutex

	readers int
	writing bool

	readCond  *sync.Cond
	writeCond *sync.Cond
}

func RwLockConstruct() *MyRwLock {
	lock := &sync.Mutex{}
	return &MyRwLock{
		mx:        lock,
		readers:   0,
		writing:   false,
		readCond:  sync.NewCond(lock),
		writeCond: sync.NewCond(lock),
	}
}

func (m *MyRwLock) RLock() {
	m.mx.Lock()
	for m.writing {
		m.readCond.Wait()
	}
	m.readers++
	defer m.mx.Unlock()
}

func (m *MyRwLock) RUnLock() {
	m.mx.Lock()
	m.readers--
	if m.readers == 0 {
		m.writeCond.Signal()
	}
	defer m.mx.Unlock()
}

func (m *MyRwLock) WriteLock() {
	m.mx.Lock()
	for m.readers > 0 || m.writing {
		m.writeCond.Wait()
	}
	m.writing = true
	defer m.mx.Unlock()
}

func (m *MyRwLock) WriteUnLock() {
	m.mx.Lock()
	m.writing = false
	m.readCond.Broadcast()
	m.writeCond.Signal()
	defer m.mx.Unlock()
}

var mySharedData int

func TryMyRWLock() {
	myRwLock := RwLockConstruct()

	wg := &sync.WaitGroup{}

	// 加三个读锁
	for i := 0; i < 5; i++ {
		wg.Add(1)

		go func(id int) {
			defer wg.Done()
			myRwLock.RLock()
			println(fmt.Sprintf("读 我是协程%v, 我读取到了sharedData: %v", id, mySharedData))
			myRwLock.RUnLock()
		}(i)
	}

	// 加三个写锁
	for i := 0; i < 5; i++ {
		wg.Add(1)

		go func(id int) {
			defer wg.Done()
			myRwLock.WriteLock()
			mySharedData++
			println(fmt.Sprintf("写 我是协程%v, 我改了sharedData: %v", id, mySharedData))
			myRwLock.WriteUnLock()
		}(i)
	}

	wg.Wait()

	println("我已经全部跑完了")

}
